﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kokomo.Mirror.Ia32;
using Kokomo.Lexical.Expressions;
using Kokomo.Lexical.Coding;
using Kokomo.PeInspector.Native.Coding;
using Kokomo.PeInspector.Reflection.Disassembly;

namespace Kokomo.PeInspector.Native
{
	public class NativeDecompiler
	{
		static NativeDecompiler()
		{
			Dictionary<Mnemonic, Action<Ia32Instruction, NativeDecompilationContext>> mnemonicTable = new Dictionary<Mnemonic, Action<Ia32Instruction, NativeDecompilationContext>>();

			// Memory
			mnemonicTable.Add(Mnemonic.mov, HandleMov);
			mnemonicTable.Add(Mnemonic.movzx, HandleMovzx);
			mnemonicTable.Add(Mnemonic.movsx, HandleMovsx);
			//mnemonicTable.Add(Mnemonic.bound, HandleBound);
			//mnemonicTable.Add(Mnemonic.arpl, HandleArpl);
			mnemonicTable.Add(Mnemonic.xchg, HandleXchg);
			mnemonicTable.Add(Mnemonic.lea, HandleLea);
			//mnemonicTable.Add(Mnemonic.xlatb, HandleXlatb);
			//mnemonicTable.Add(Mnemonic.cmpxchg, HandleCmpxchg);
			//mnemonicTable.Add(Mnemonic.cmpxch8b, HandleCmpxch8b);
			mnemonicTable.Add(Mnemonic.cmovo, HandleCmovo);
			mnemonicTable.Add(Mnemonic.cmovno, HandleCmovno);
			mnemonicTable.Add(Mnemonic.cmovb, HandleCmovb);
			mnemonicTable.Add(Mnemonic.cmovae, HandleCmovae);
			mnemonicTable.Add(Mnemonic.cmove, HandleCmove);
			mnemonicTable.Add(Mnemonic.cmovne, HandleCmovne);
			mnemonicTable.Add(Mnemonic.cmovbe, HandleCmovbe);
			mnemonicTable.Add(Mnemonic.cmova, HandleCmova);
			mnemonicTable.Add(Mnemonic.cmovs, HandleCmovs);
			mnemonicTable.Add(Mnemonic.cmovns, HandleCmovns);
			mnemonicTable.Add(Mnemonic.cmovp, HandleCmovp);
			mnemonicTable.Add(Mnemonic.cmovnp, HandleCmovnp);
			mnemonicTable.Add(Mnemonic.cmovl, HandleCmovl);
			mnemonicTable.Add(Mnemonic.cmovge, HandleCmovge);
			mnemonicTable.Add(Mnemonic.cmovle, HandleCmovle);
			mnemonicTable.Add(Mnemonic.cmovg, HandleCmovg);
			// Arithmetic
			mnemonicTable.Add(Mnemonic.add, HandleAdd);
			mnemonicTable.Add(Mnemonic.sub, HandleSub);
			// Logical
			mnemonicTable.Add(Mnemonic.and, HandleAnd);
			mnemonicTable.Add(Mnemonic.xor, HandleXor);
			// Testing
			mnemonicTable.Add(Mnemonic.cmp, HandleCmp);
			mnemonicTable.Add(Mnemonic.test, HandleTest);
			// Stack
			mnemonicTable.Add(Mnemonic.push, HandlePush);
			mnemonicTable.Add(Mnemonic.pop, HandlePop);
			// Flow
			mnemonicTable.Add(Mnemonic.jmp, HandleJump);
			mnemonicTable.Add(Mnemonic.call, HandleCall);
			mnemonicTable.Add(Mnemonic.ret, HandleReturn);
			mnemonicTable.Add(Mnemonic.jo, HandleJmpo);
			mnemonicTable.Add(Mnemonic.jno, HandleJmpno);
			mnemonicTable.Add(Mnemonic.jb, HandleJmpb);
			mnemonicTable.Add(Mnemonic.jae, HandleJmpae);
			mnemonicTable.Add(Mnemonic.je, HandleJmpe);
			mnemonicTable.Add(Mnemonic.jne, HandleJmpne);
			mnemonicTable.Add(Mnemonic.jbe, HandleJmpbe);
			mnemonicTable.Add(Mnemonic.ja, HandleJmpa);
			mnemonicTable.Add(Mnemonic.js, HandleJmps);
			mnemonicTable.Add(Mnemonic.jns, HandleJmpns);
			mnemonicTable.Add(Mnemonic.jp, HandleJmpp);
			mnemonicTable.Add(Mnemonic.jnp, HandleJmpnp);
			mnemonicTable.Add(Mnemonic.jl, HandleJmpl);
			mnemonicTable.Add(Mnemonic.jge, HandleJmpge);
			mnemonicTable.Add(Mnemonic.jle, HandleJmple);
			mnemonicTable.Add(Mnemonic.jg, HandleJmpg);

			_mnemonicHandlerTable = mnemonicTable;
		}

		#region Helper functions
		public static Type GetTypeForOperandSize(
			OperandSize size,
			bool signed
			)
		{
			Type type;
			switch (size)
			{
				case OperandSize.Byte:
					type = (signed ? typeof(sbyte) : typeof(byte));
					break;
				case OperandSize.Word:
					type = (signed ? typeof(short) : typeof(ushort));
					break;
				case OperandSize.Dword:
					type = (signed ? typeof(int) : typeof(uint));
					break;
				case OperandSize.Qword:
					type = (signed ? typeof(long) : typeof(ulong));
					break;
				//case OperandSize.DQword:
				//    type = 
				//    break;
				//case OperandSize.Bytes6:
				//    break;
				default:
					throw new ArgumentException();
			}

			return type;
		}
		private static Expression GetStatusConditionExpression(
			StatusCondition condition,
			NativeDecompilationContext context
			)
		{
			Expression expression;
			switch (condition)
			{
				case StatusCondition.Overflow:
					expression = context.GetFlag(Eflags.Overflow).Value;
					break;
				case StatusCondition.NotOverflow:
					expression = !context.GetFlag(Eflags.Overflow).Value;
					break;
				case StatusCondition.Below:
					expression = context.GetFlag(Eflags.Carry).Value;
					break;
				case StatusCondition.AboveOrEqual:
					expression = !context.GetFlag(Eflags.Carry).Value;
					break;
				case StatusCondition.Equal:
					expression = context.GetFlag(Eflags.Zero).Value;
					break;
				case StatusCondition.NotEqual:
					expression = !context.GetFlag(Eflags.Zero).Value;
					break;
				case StatusCondition.BelowOrEqual:
					expression = Expression.op_LogicalOr(context.GetFlag(Eflags.Carry).Value, context.GetFlag(Eflags.Zero).Value);
					break;
				case StatusCondition.Above:
					expression = Expression.op_LogicalAnd(!context.GetFlag(Eflags.Carry).Value, !context.GetFlag(Eflags.Zero).Value);
					break;
				case StatusCondition.Sign:
					expression = context.GetFlag(Eflags.Sign).Value;
					break;
				case StatusCondition.NotSign:
					expression = !context.GetFlag(Eflags.Sign).Value;
					break;
				case StatusCondition.Parity:
					expression = context.GetFlag(Eflags.Parity).Value;
					break;
				case StatusCondition.NotParity:
					expression = !context.GetFlag(Eflags.Parity).Value;
					break;
				case StatusCondition.Less:
					expression = Expression.Inequality(context.GetFlag(Eflags.Sign).Value, context.GetFlag(Eflags.Overflow).Value);
					break;
				case StatusCondition.GreaterOrEqual:
					expression = Expression.Equality(context.GetFlag(Eflags.Sign).Value, context.GetFlag(Eflags.Overflow).Value);
					break;
				case StatusCondition.LessOrEqual:
					expression = Expression.op_LogicalOr(context.GetFlag(Eflags.Zero).Value, Expression.Inequality(context.GetFlag(Eflags.Sign).Value, context.GetFlag(Eflags.Overflow).Value));
					break;
				case StatusCondition.Greater:
					expression = Expression.op_LogicalAnd(!context.GetFlag(Eflags.Zero).Value, Expression.Equality(context.GetFlag(Eflags.Sign).Value, context.GetFlag(Eflags.Overflow).Value));
					break;
				default:
					throw new ArgumentException("Invalid condition", "condition");
			}

			return expression;
		}
		#endregion

		private static Dictionary<Mnemonic, Action<Ia32Instruction, NativeDecompilationContext>> _mnemonicHandlerTable;

		public static NativeProcedureDecompilation Decompile(NativeProcedureInfo procedure)
		{
			if (procedure == null) throw new ArgumentNullException("procedure");

			Ia32Disassembly disassembly = procedure.Disassemble();
			NativeDecompilationContext context = new NativeDecompilationContext(disassembly);
			while (context.MoveNext())
			{
				Ia32Instruction instruction = context.CurrentInstruction;
				Action<Ia32Instruction, NativeDecompilationContext> handler;

				try
				{
					if (_mnemonicHandlerTable.TryGetValue(instruction.OpCode.Mnemonic, out handler))
					{
						handler(instruction, context);
					}
					else
					{
						Expression[] arguments = new Expression[instruction.Operands.Length];
						for (int i = 0; i < instruction.Operands.Length; i++)
						{
							arguments[i] = context.OperandToLineage(instruction.Operands[i]).Value;
						}

						InstructionStatement statement = new InstructionStatement(instruction, arguments);
						context.Statements.Add(statement);
						//throw new UnrecognizedMnemonicException(context.CurrentInstruction.OpCode.Mnemonic);
					}
				}
				catch (Exception exception)
				{
					throw new DecompilationException(context.CurrentInstruction, exception);
				}
			}

			NativeProcedureDecompilation decompilation = new NativeProcedureDecompilation(
				procedure,
				context.Statements
				);

			return decompilation;
		}

		#region Handlers
		#region Memory
		private static void HandleMov(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			if (object.Equals(instruction.Operands[0], instruction.Operands[1])) return;

			NativeVariableLineage lineage = context.LoadOperand(instruction.Operands[1]);
			context.SetOperand(
				instruction.Operands[0],
				lineage.Value,
				lineage.InferredType,
				lineage
				);
		}
		private static void HandleMovzx(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage lineage = context.LoadOperand(instruction.Operands[1]);
			context.SetOperand(
				instruction.Operands[0],
				lineage.Value,
				GetTypeForOperandSize(instruction.Operands[1].Size, false),
				lineage
				);
		}
		private static void HandleMovsx(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage lineage = context.LoadOperand(instruction.Operands[1]);
			context.SetOperand(
				instruction.Operands[0],
				lineage.Value,
				GetTypeForOperandSize(instruction.Operands[1].Size, true),
				lineage
				);
		}
		private static void HandleLea(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage lineage = context.LoadOperand(instruction.Operands[1]);
			context.SetOperand(
				instruction.Operands[0],
				new IndirectExpression(lineage.Value),
				typeof(IntPtr),
				lineage
				);
		}
		private static void HandleXchg(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			if (object.Equals(instruction.Operands[0], instruction.Operands[1])) return;

			NativeVariableLineage leftTarget = context.LoadOperand(instruction.Operands[0]);
			NativeVariableLineage rightTarget = context.LoadOperand(instruction.Operands[1]);

			context.SetOperand(
				instruction.Operands[0],
				rightTarget.Value,
				rightTarget.InferredType,
				rightTarget
				);

			context.SetOperand(
				instruction.Operands[1],
				leftTarget.Value,
				leftTarget.InferredType,
				leftTarget
				);
		}

		#region Conditional moves
		private static void HandleConditionalMove(
			Ia32Instruction instruction,
			NativeDecompilationContext context,
			StatusCondition condition
			)
		{
			if (object.Equals(instruction.Operands[0], instruction.Operands[1])) return;

			Expression conditionExpression = GetStatusConditionExpression(
				condition,
				context
				);

			NativeVariableLineage lineage = context.LoadOperand(instruction.Operands[1]);

			context.SetOperand(
				instruction.Operands[0],
				lineage.Value,
				lineage.InferredType,
				lineage
				);
		}
		private static void HandleCmovo(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Overflow
				);
		}
		private static void HandleCmovno(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.NotOverflow
				);
		}
		private static void HandleCmovb(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Below
				);
		}
		private static void HandleCmovae(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.AboveOrEqual
				);
		}
		private static void HandleCmove(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Equal
				);
		}
		private static void HandleCmovne(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.NotEqual
				);
		}
		private static void HandleCmovbe(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.BelowOrEqual
				);
		}
		private static void HandleCmova(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Above
				);
		}
		private static void HandleCmovs(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Sign
				);
		}
		private static void HandleCmovns(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.NotSign
				);
		}
		private static void HandleCmovp(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Parity
				);
		}
		private static void HandleCmovnp(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.NotParity
				);
		}
		private static void HandleCmovl(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Less
				);
		}
		private static void HandleCmovge(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.GreaterOrEqual
				);
		}
		private static void HandleCmovle(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.LessOrEqual
				);
		}
		private static void HandleCmovg(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalMove(
				instruction,
				context,
				StatusCondition.Greater
				);
		}
		#endregion
		#endregion

		#region Arithmetic
		private static void HandleAdd(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			Register leftRegister = instruction.Operands[0] as Register;
			ImmediateOperand rightImmediate = instruction.Operands[1] as ImmediateOperand;
			if (
				(leftRegister != null)
				&& (context.IsStackPointer(leftRegister))
				&& (rightImmediate != null)
				)
			{
				context.DeallocateStackFrame((int)rightImmediate.Value);
			}
			else
			{
				NativeVariableLineage left = context.LoadOperand(instruction.Operands[1]);
				NativeVariableLineage right = context.LoadOperand(instruction.Operands[1]);
				NativeVariableLineage result = context.SetOperand(
					instruction.Operands[0],
					left.Value + right.Value,
					left.InferredType,
					left, right
					);

				context.SetArithmeticFlags(result);
			}
		}
		private static void HandleSub(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			Register leftRegister = instruction.Operands[0] as Register;
			ImmediateOperand rightImmediate = instruction.Operands[1] as ImmediateOperand;
			if (
				(leftRegister != null)
				&& (context.IsStackPointer(leftRegister))
				&& (rightImmediate != null)
				)
			{
				context.AllocateStackFrame((int)rightImmediate.Value);
			}
			else
			{
				NativeVariableLineage left = context.LoadOperand(instruction.Operands[1]);
				NativeVariableLineage right = context.LoadOperand(instruction.Operands[1]);
				context.SetOperand(
					instruction.Operands[0],
					left.Value - right.Value,
					left.InferredType,
					left, right
					);

				NativeVariableLineage result = context.LoadOperand(instruction.Operands[0]);
				context.SetArithmeticFlags(result);
			}
		}
		#endregion
		#region Logical
		private static void HandleAnd(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage left = context.LoadOperand(instruction.Operands[1]);
			NativeVariableLineage right = context.LoadOperand(instruction.Operands[1]);

			if (instruction.Operands[1].Equals(new ImmediateOperand(instruction.Operands[1].Size, 0)))
			{
				context.SetOperand(
					instruction.Operands[0],
					ConstantExpression.ZeroInt,
					left.InferredType
				);
				context.SetFlag(Eflags.Zero, BooleanConstantExpression.True);
				context.SetFlag(Eflags.Parity, BooleanConstantExpression.True);
				context.SetFlag(Eflags.Sign, BooleanConstantExpression.False);
			}
			else
			{
				context.SetOperand(
					instruction.Operands[0],
					left.Value & right.Value,
					left.InferredType,
					left, right
					);
				NativeVariableLineage result = context.LoadOperand(instruction.Operands[0]);
				context.SetLogicalFlags(result);
			}
			context.SetFlag(Eflags.Overflow, BooleanConstantExpression.False);
			context.SetFlag(Eflags.Carry, BooleanConstantExpression.False);
		}
		private static void HandleXor(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage left = context.LoadOperand(instruction.Operands[1]);
			NativeVariableLineage right = context.LoadOperand(instruction.Operands[1]);

			if (left.Value.Equals(right.Value))
			{
				context.SetOperand(
					instruction.Operands[0],
					ConstantExpression.ZeroInt,
					left.InferredType
					);
				context.SetFlag(Eflags.Zero, BooleanConstantExpression.True);
				context.SetFlag(Eflags.Parity, BooleanConstantExpression.True);
				context.SetFlag(Eflags.Sign, BooleanConstantExpression.False);
			}
			else
			{
				context.SetOperand(
					instruction.Operands[0],
					left.Value + right.Value,
					left.InferredType,
					left, right
					);
				NativeVariableLineage result = context.LoadOperand(instruction.Operands[0]);
				context.SetLogicalFlags(result);
			}
			context.SetFlag(Eflags.Overflow, BooleanConstantExpression.False);
			context.SetFlag(Eflags.Carry, BooleanConstantExpression.False);
		}
		#endregion

		#region Testing
		private static void HandleCmp(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage left = context.LoadOperand(instruction.Operands[1]);
			NativeVariableLineage right = context.LoadOperand(instruction.Operands[1]);
			Expression result = left.Value - right.Value;

			NativeVariableLineage lineage = new NativeVariableLineage(
				result,
				context.CurrentOffset,
				left.InferredType,
				left, right
				);
			context.SetArithmeticFlags(lineage);
		}
		private static void HandleTest(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage left = context.LoadOperand(instruction.Operands[1]);
			NativeVariableLineage right = context.LoadOperand(instruction.Operands[1]);

			if (instruction.Operands[1].Equals(new ImmediateOperand(instruction.Operands[1].Size, 0)))
			{
				NativeVariableLineage lineage= new NativeVariableLineage(
					ConstantExpression.ZeroInt,
					context.CurrentOffset,
					left.InferredType
				);
				context.SetFlag(Eflags.Zero, BooleanConstantExpression.True);
				context.SetFlag(Eflags.Parity, BooleanConstantExpression.True);
				context.SetFlag(Eflags.Sign, BooleanConstantExpression.False);
			}
			else
			{
				NativeVariableLineage lineage = new NativeVariableLineage(
					left.Value & right.Value,
					context.CurrentOffset,
					left.InferredType,
					left, right
				);
				context.SetLogicalFlags(lineage);
			}
			context.SetFlag(Eflags.Overflow, BooleanConstantExpression.False);
			context.SetFlag(Eflags.Carry, BooleanConstantExpression.False);
		}
		#endregion

		#region Stack
		private static void HandlePush(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage lineage = context.LoadOperand(instruction.Operands[0]);
			context.Push(lineage.Value, lineage.InferredType);
		}
		private static void HandlePop(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			NativeVariableLineage lineage = context.Pop();
			context.SetOperand(instruction.Operands[0], lineage.Value, lineage.InferredType);
		}
		#endregion
		#region Flow
		private static void HandleJump(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			context.OnBranching();
			context.Statements.Add(new BranchStatement(new Label(instruction.Operands[0].ToString())));
		}
		private static void HandleCall(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			context.OnBranching();

			Expression target = context.OperandToLineage(instruction.Operands[0]).Value;
			context.Statements.Add(new CallStatement(target));
		}
		private static void HandleReturn(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			Expression returnValue = context.LoadOperand(Registers.RAX).Value;
			context.Statements.Add(new ReturnStatement(returnValue));

			//Expression target = context.OperandToLineage(instruction.Operands[0]).Value;
			//context.Statements.Add(new CallStatement(target));
		}
		#region Conditional jumps
		private static void HandleConditionalJump(
			Ia32Instruction instruction,
			NativeDecompilationContext context,
			StatusCondition condition
			)
		{
			JumpTarget target = (JumpTarget)instruction.Operands[0];

			context.OnBranching();
			Expression conditionExpression = GetStatusConditionExpression(
				condition,
				context
				);

			ConditionStatement conditional = new ConditionStatement(conditionExpression);
			conditional.TrueStatements.Add(new BranchStatement(new Label(target.TargetOffset.ToString("X"))));
			context.Statements.Add(conditional);
		}
		private static void HandleJmpo(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Overflow
				);
		}
		private static void HandleJmpno(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.NotOverflow
				);
		}
		private static void HandleJmpb(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Below
				);
		}
		private static void HandleJmpae(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.AboveOrEqual
				);
		}
		private static void HandleJmpe(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Equal
				);
		}
		private static void HandleJmpne(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.NotEqual
				);
		}
		private static void HandleJmpbe(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.BelowOrEqual
				);
		}
		private static void HandleJmpa(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Above
				);
		}
		private static void HandleJmps(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Sign
				);
		}
		private static void HandleJmpns(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.NotSign
				);
		}
		private static void HandleJmpp(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Parity
				);
		}
		private static void HandleJmpnp(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.NotParity
				);
		}
		private static void HandleJmpl(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Less
				);
		}
		private static void HandleJmpge(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.GreaterOrEqual
				);
		}
		private static void HandleJmple(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.LessOrEqual
				);
		}
		private static void HandleJmpg(Ia32Instruction instruction, NativeDecompilationContext context)
		{
			HandleConditionalJump(
				instruction,
				context,
				StatusCondition.Greater
				);
		}
		#endregion
		#endregion
		#endregion
	}
}
